﻿using System.Collections.Generic;
using System.Text;

namespace FluentTagsGenerator
{
    class MethodGenerator
    {
        const string _genericElementTemplate = @"
        public ${Element}Tag<${Class}Tag> ${Element}()
        {
            var ctrl = new ${Element}Tag<${Class}Tag>(this);
            Controls.Add(ctrl);
            return ctrl;
        }

        public ${Class}Tag ${Element}(${Element}Tag child)
        {
            Controls.Add(child);
            return this;
        }
        ";

        const string _genericElementTextTemplate = @"
        public ${Element}Tag<${Class}Tag> ${Element}(string text)
        {
            var ctrl = new ${Element}Tag<${Class}Tag>(this);
            Controls.Add(ctrl);
            LiteralControl lc = new LiteralControl(text);
            ctrl.Controls.Add(lc);
            
            return ctrl;
        }

        public ${Element}Tag<${Class}Tag> ${Element}(Control control)
        {
            var ctrl = new ${Element}Tag<${Class}Tag>(this);
            Controls.Add(ctrl);
            ctrl.Controls.Add(control);
            
            return ctrl;
        }

        public ${Element}Tag<${Class}Tag> ${Element}(object value)
        {
            return ${Element}(SafeString(value));
        }
        ";


        const string _genericParentElementTemplate = @"
        public ${Element}Tag<${Class}Tag<ParentType>> ${Element}()
        {
            var ctrl = new ${Element}Tag<${Class}Tag<ParentType>>(this);
            Controls.Add(ctrl);
            return ctrl;
        }

        public ${Class}Tag<ParentType> ${Element}(${Element}Tag child)
        {
            Controls.Add(child);
            return this;
        }
        ";

        const string _genericParentElementTextTemplate = @"
        public ${Element}Tag<${Class}Tag<ParentType>> ${Element}(string text)
        {
            var ctrl = new ${Element}Tag<${Class}Tag<ParentType>>(this);
            LiteralControl lc = new LiteralControl(text);
            Controls.Add(ctrl);
            ctrl.Controls.Add(lc);
            
            return ctrl;
        }

        public ${Element}Tag<${Class}Tag<ParentType>> ${Element}(Control control)
        {
            var ctrl = new ${Element}Tag<${Class}Tag<ParentType>>(this);
            Controls.Add(ctrl);
            ctrl.Controls.Add(control);
            
            return ctrl;
        }

        public ${Element}Tag<${Class}Tag<ParentType>> ${Element}(object value)
        {
            var ctrl = new ${Element}Tag<${Class}Tag<ParentType>>(this);
            LiteralControl lc = new LiteralControl(SafeString(value));
            Controls.Add(ctrl);
            ctrl.Controls.Add(lc);
            return ctrl;
        }
        ";

        public string ClassName { get; private set; }
        public StringBuilder ClassContent { get; private set; }
        public List<TagElement> Elements { get; private set; }

        public MethodGenerator(string className, StringBuilder classContent, List<TagElement> elements)
        {
            ClassName = className;
            ClassContent = classContent;
            Elements = elements;
            
        }

        public StringBuilder Generate()
        {
            ClassContent = GenerateMethods(_genericElementTemplate, _genericElementTextTemplate, "${genericMethods}");
            ClassContent = GenerateMethods(_genericParentElementTemplate, _genericParentElementTextTemplate, "${genericParentMethods}");

            return ClassContent;
        }

        private StringBuilder GenerateMethods(string methodCreateGenericElementTemplate, string methodCreateGenericElementTextTemplate, string toReplace)
        {
            var methodText = GenerateElementCreateMethods(methodCreateGenericElementTemplate, methodCreateGenericElementTextTemplate);

            ClassContent = ClassContent.Replace(toReplace, methodText);
            return ClassContent;
        }

        private string GenerateElementCreateMethods(string methodCreateGenericElementTemplate, string methodCreateGenericElementTextTemplate)
        {
            StringBuilder sb = new StringBuilder();

            foreach (TagElement ele in Elements)
            {
                sb.Append(
                    methodCreateGenericElementTemplate
                    .Replace("${Class}", ClassName)
                    .Replace("${Element}", CSharpNaming.ClassifyName(ele.Name)));

                if (ele.IsText)
                {
                    sb.Append(
                        methodCreateGenericElementTextTemplate
                        .Replace("${Class}", ClassName)
                        .Replace("${Element}", CSharpNaming.ClassifyName(ele.Name)));

                }
            }

            return sb.ToString();
        }
        
    }
}
